home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume91 / devices / virtalph / part04 / virtual.c
C/C++ Source or Header  |  1991-05-08  |  59KB  |  2,161 lines

  1. /*
  2.     about this project:
  3.  
  4.     I started doing this thing in M.L. ( FindHandler is a remnant) but
  5.     then I realized I wanted to explore Handlers, not the Age of the
  6.     Universe.
  7.  
  8.     But! luckily I encountered this fine piece of work by a
  9.     certain guy named *** Matt Dillion *** ; perhaps you've heard of him,
  10.     here's a guy who's making the best of the terrible misfortune to
  11.     have been born with eight arms; and the reflexes of a fly ;-)
  12.  
  13.     yours truly anselm
  14.  */
  15.  
  16. #define NOBECOLORS
  17. #define BEVIRTUAL
  18.  
  19.  
  20. #include "dos.h"
  21.  
  22.  
  23. #define MakeID(a,b,c,d)  ( (LONG)(a)<<24L | (LONG)(b)<<16L | (c)<<8 | (d) )
  24. #define VIRT    MakeID('V','I','R','T')
  25.  
  26. int myreadsome(ubyte *,FENTRY *,int);
  27. int andycode(char *,MYFH *,PACKET *);
  28.  
  29. /*
  30.     THE FOLLOWING IS A REVIEW OF THE APPROACH I TOOK TO SOLVING THE
  31.     PROBLEM OF THIS HANDLER NOT COMPILING PROPERLY UNDER LATTICE 5.10
  32.  
  33.     It should serve as general help on writing MANX compatible code,
  34.     code using the AMIGADOS CreateProc, and nailing bugs in LATTICE 5.10.
  35.  
  36.     (this review was released as an informative guide to some of the
  37.      pitfalls of C programming, and as a bit of humour about just how
  38.      yuchy things can get sometimes :)  Anselm Hook - Jan 21 1991. )
  39.  
  40.     (this exploration was evolved over a 3 day period at about 8 hours
  41.      a day (my computer is very slow) (now i know why people use machine
  42.      code; comparatively in 3 days worth of time we mostly wrote DATASTORM
  43.      (admittedly at 24 hours a day but....) )
  44.  
  45.     ( I bothered with this analysis because of the inexplicable erratic
  46.       nature of the bugs, and the dependancy i was experiencing on
  47.       an enviroment i didn't fully understand...now that I've solved the
  48.       problem this analysis will service me in the future, and the general
  49.       knowledge i've acquired should help me design around potential
  50.       catastrophes like this; all of this applies particularily when i
  51.       try to do some really heavy coding in C++)).
  52.  
  53.  
  54.  
  55. compiling pitfalls:
  56.  
  57.  
  58. GENERAL:
  59.  
  60. linker
  61.     VERBOSE NOALVS  both have no effect
  62.  
  63.     SC SD
  64.  
  65.     ***    if both are set then _sprintf attempts to use (a4) base
  66.         relative addressing.  However base relative addressing
  67.         is not enabled, so the system crashes.
  68.  
  69.         Presumably if the -y option is set in the program then
  70.         base relative addressing will magically become functional;
  71.         except that I'm not certain if the system has been given
  72.         space for _sprintf to use...which may mean that rather than
  73.         crashing right away it just trashes local memory for a while.
  74.  
  75.         (we'll have to try -y, and SC, SD seperately and combined)
  76.  
  77.     SC
  78.         WHEN REMOVED: (and -v -b0 -r are on)
  79.         - modifies the addresses accessed by (a4), however a4 is
  80.           still not initialized.  Note that all of my code seems to
  81.           be OK, its just the linked in system support code that is
  82.           attempting to use the uninitialized a4.
  83.  
  84.         - some symbols become indirect (less visible too)
  85.  
  86.     SD
  87.         WHEN REMOVED:  (and -v -b0 -r are on)
  88.         - does fix problem of code trying to use (a4)
  89.         - code seems to call the wrong addresses or something weird
  90.         - freezes up and dies when trying to "findport"
  91.  
  92.  
  93.     NODEBUG  actually helps supply debug symbols, I don't know why...
  94.  
  95.     ADDSYM    must have NODEBUG present, and if NODEBUG is set then
  96.         this must be present or the file won't be executable
  97.         (for some reason).
  98.  
  99.     in general doesn't bitch as profluently if lcm.lib is left out.
  100.  
  101. compiler
  102.  
  103.     sometimes ABSEXECBASE is 0  - I don't know why, may be BLINKS fault
  104.  
  105.     -r  = pc relative addressing (but not base relative???)
  106.           seems to work when this is on.
  107.  
  108.     -y  = reload a4 always, seems to make package fail, i'm not
  109.           sure why, but i did notice that it did not set A4 as
  110.           it promised, furthermore that A4 was (or became required).
  111.         (actually this is due to SC SD i think)
  112.  
  113.     -b0 = does something, I'm not exactly sure what
  114.           so far i haven't got it to work without -b0
  115.           Ok -> -b is ON by default, thats why -b has no effect, and
  116.           -b0 turns it off (base register relative mode addressing)
  117.  
  118.           -b0 definately makes it not require a4,
  119.            ABSEXECBASE is wrong still however (a6).
  120.         (actually still requires A4 depending on SC SD setting)
  121.  
  122.     -v = disable stack checking, does help (although I don't know why).
  123.  
  124.           interestingly enough the linker will fail unless this option
  125.           is set.  The linker appears to be looking for some variables
  126.           to give it position specific guidance if -v is on.
  127.  
  128.           IF ONLY -V is set then the program will fail when it
  129.           trys to access relative to (a4).
  130.  
  131.     -d = not important.  but to access debugging info in general:
  132.  
  133.          turn ADDSYM on in linker then:
  134.  
  135.          debug on...this works ok, to trap the handler run 2 copies of
  136.          DB, do an 'al' on "cd device", then set a second 'al' on
  137.          second DB once first one has trapped the 'cd', then quit
  138.          the first one - the cd will run, and then try start up the
  139.          device process, at which point the second db catches it, and
  140.          if you are in the right directory it will load up the properly
  141.          named symbol table.
  142.  
  143.  
  144.  
  145.  
  146. DIFFERENT ATTEMPTS:
  147.  
  148. one:
  149.     using -v -b0 -r    and SC SD ADDSYM
  150.  
  151.     with my code:
  152.         FINDPORT = hang point        - doesn't reach debug window
  153.  
  154.     without my code:
  155.         SPRINTF = hang point (missing (a4)) - gets as far as debug window
  156.  
  157. two:
  158.     using -v -b -r -y and ADDSYM SC SD  (may change code size, erratic result?)
  159.  
  160.     with my code:
  161.         (it should crash at FINDPORT still)
  162.         (no purpose in trying if below crashes)
  163.  
  164.     without my code:
  165.         (it should work ok)
  166.         actually crashes still, still missing (a4) at _sprintf
  167.  
  168. three:
  169.     -v -r -y -b0 and ADDSYM SC SD ADDSYM
  170.  
  171.     without my code:
  172.         still misses (a4) at sprintf
  173.  
  174. four:
  175.     -v -b0, SC SD (without my code)
  176.  
  177.     - works, doesn't try to access a4
  178.     - obviously the -r is forcing a base relative addressing on.
  179.     - and -y just doesn't ever work.
  180.     - notably some tasks in system at same time crash on exiting
  181.     - notably (a4) seems to point to something although its not used
  182.  
  183. five:
  184.     -v -b0, SC SD ADDSYM (without my code)
  185.  
  186.     - exactly same response as (four)
  187.     - (including types of crashes etc.  DEBUG doesn't seem to have bad fx)
  188.  
  189. six:
  190.     -b0 SC SD ADDSYM (without my code)
  191.  
  192.     - complains about missing link time stuff _StackPtr etc...
  193.  
  194. seven:
  195.     -v -b0, SC SD ADDSYM WITH-MY-CODE
  196.  
  197.     crashes in this way:
  198.  
  199.     _typetostr+12c
  200.         jsr _typetostr+18a
  201.             (sysbase is corrupt incidentally)
  202.             _pf+46
  203.             (crashes here, A4 is not initialized, yet required!)
  204.             (works fine from here on - if i force A4 to be valid)
  205.             _strupr+2
  206.             _dbinit
  207.     _typetostr+130
  208.  
  209. eight:
  210.     -v -b0 NO-MY-CODE, NO SC SC, JUST ADDSYMS
  211.  
  212.     freezes up (at findport i believe) - forever.
  213.  
  214. nine:
  215.     -v -b0    ....no blink options, none of my code
  216.  
  217.     freezes up exactly same... (thus ADDSYM definately has no effect)
  218.  
  219.     BLINK states that SC SD makes any object module that was compiled
  220.     with -b use it.  Even if I disable -b, blink is still going to
  221.     throw in some system modules using it if i set SC SD.  This is
  222.     why code can be referencing (a4) when its not enabled by compiler.
  223.  
  224.     Interestingly enough I noticed that _pf+46 was not supposed to
  225.     fall through to _strupr+2, when recompiled without SC SD, this
  226.     may be another bug. (actually i believe this is because i was
  227.     using an old symbol table, as i just found out)
  228.  
  229.     Altogether there are then these bugs I have seen:
  230.         1) use of (a4) illegally
  231.         2) bad init on SysBase  (probably not)
  232.         3) bad code (probably not actually)
  233.         4) freeze up waiting for port sig (bad sysbase?)
  234.  
  235.     I have figured out:
  236.         1) kindof my fault, anyway I can avoid it
  237.         2) no idea? perhaps debugger is showing wrong address? (no see 3)
  238.         3) no idea? perhaps compiler bug? (is bad symbol table)
  239.         4) perhaps bad sysbase?
  240.  
  241.     ok so bugs are:
  242.         1) (a4) use...fixed
  243.         4) freeze waiting for port -> createproc failed?
  244.  
  245.     Notably the reason it doesn't run with my code, and crashes externals
  246.     is due to (a4) causing erratic crash behavior.  That is definately
  247.     fixed now.  It would be nice to have a proper A4 however, and possibly
  248.     i can try use the -y to force it on, or check some code from the
  249.     lattice support startup source to see how they do it properly.
  250.  
  251.     unknown:
  252.         major is why should it freeze waiting for port sig if
  253.         the silly SC SD is not set? its gotta be a sysbase problem
  254.         cause sysbase was corrupt before, but maybe not needed.
  255.  
  256. *** NEWS BULLETIN ***
  257.  
  258.     the reason for bug #4 is very very bad....
  259.  
  260.     Matt patched in a hunk of machine code such that no matter what
  261.     happened the BCPL<<C segment would hit approximately the right
  262.     area and get funneled off to where it belonged.
  263.  
  264.     When I *don't* use a SMALLCODE SMALLDATA model, the operation
  265.     gets indexed through a JUMP TABLE!!!! and of course %78 of the
  266.     time it fucks up; the BCPL<<C being potentially off 2 in either
  267.     direction...at run time...
  268.  
  269.     so - i know you're all waiting in breathless anticipation -
  270.  
  271.     how do i solve it!!!?
  272.  
  273.     maybe ARP has a createproc of its own... [ nope ]
  274.  
  275.     hmmm...
  276.  
  277.     [ TECHNICALLY THIS IS A BUG IN LATTICE 5.10 for permitting jump
  278.       tables on non-longword aligned addresses - because surely DOS
  279.       must load longword aligned? (now that i think about it) ]
  280.  
  281.     i guess maybe what lattice does is just keep functions longword
  282.     aligned? (lets check) [ NOPE ]
  283.  
  284.     [ this is probably why historically I've never been able to
  285.       get CreateProc to work, actually when I first wanted to try
  286.       a "neato" function like that I presumably didn't even cast
  287.       the function pointer as a BCPL... ]
  288.  
  289.     an easy way to check if the bug has been resolved is to
  290.     just look at _debugproc
  291.  
  292.     - we basically must remove this call from the jump table...
  293.  
  294.     - _builtin_ is a way  [ but its a mess! ]
  295.  
  296.     - r may solve this...but lets really deal with it... [ NAH JUST DO IT ]
  297.  
  298.     [ -r does not remove the jump table...therefore it doesn't help ]
  299.  
  300.     - lets try base relative? (just once?)
  301.       ok config is now:
  302.         -v -y -r,  ADDSYM, MY-CODE-ON    (and -b on by default)
  303.  
  304.     - now SysBase is wrong *AND* debugproc still jumps via library ref!!!
  305.  
  306.       (why the fuck is SysBase wrong???)
  307.  
  308.       SysBase is wrong because - get this - its accessed off of (A4) now,
  309.       and *(4(a4)) is something other than *(4(0))
  310.  
  311.       ABSEXECBASE became a *variable* with an ABSOLUTE delta offset of
  312.       4 into the program data block; versus being ABSOLUTE in the vernacular
  313.       logically correct sense...it has choosen to a be groovier, cooler
  314.       kind of ABSEXECBASE than all those other squares...
  315.  
  316.       This is partly Matts fault because of his damned "void *"'s but
  317.       lattice clearly made a compile mistake.
  318.  
  319.     OK, lets just fix SysBase, and turn on SC SD to hopefully kill the
  320.     jump table...
  321.  
  322.     *Y*E*S*  FUCK ME BLUE it worked....
  323.  
  324.     Ok so the jump table is axed, and the only system reference that
  325.     I encountered is fixed...hopefully there aren't any other defines
  326.     like that...[ there appear not to be any ].
  327.  
  328.     Ok now the bugs were:
  329.  
  330.         1) ABSEXECBASE was referenced as an external void *; which
  331.            to lattice could mean fucking anything...so naturally it
  332.            became consumed into the compiler as a "variable" versus
  333.            whatever it really was.
  334.  
  335.            Despite understanding it, i would still say this is a bug
  336.            in lattice 5.10 (mostly).
  337.  
  338.         2) The Jump Tables.  Should be longword aligned.  I would
  339.            say that this is a bug; because its something unexpected
  340.            and non-obvious to the casual user.  Especially in an
  341.            Amiga Enviroment where BCPL DOS requires longword
  342.            alignment.  So this is also a bug in Lattice 5.10.
  343.  
  344.  
  345.     *** the end of this 3 day debug session ***
  346.  
  347.  
  348. Now we have a bug where:
  349.  
  350.     my readsome bad values, as compared to submitted values
  351.  
  352.     possible problems:
  353.  
  354.         1) void * (again) treated as not long sometimes?
  355.            but then it should freak everywhere
  356.         2) structure passed on stack, not just address
  357.  
  358. BUG:  DOSDevice isn't pointed right from M.L...
  359.  
  360.     doesn't handle pc relative?
  361.  
  362.  
  363.  *  DOSDEVICE.C     V1.10    2 November 1987
  364.  *
  365.  *  EXAMPLE DOS DEVICE DRIVER FOR AZTEC.C   PUBLIC DOMAIN.
  366.  *
  367.  *  By Matthew Dillon.
  368.  *
  369.  *  Debugging routines are disabled by simply attempting to open the
  370.  *  file "debugoff", turned on again with "debugon".  No prefix may be
  371.  *  attached to these names (you must be CD'd to TEST:).
  372.  *
  373.  *  See Documentation for a detailed discussion.
  374.  *
  375.  *  BUGS:
  376.  *    Currently the only known bug is with the implementation of the
  377.  *    RAM disk itself.  Specifically, if filehandle A is at the end of
  378.  *    the file, and somebody appends to the file with another filehandle,
  379.  *    B, filehandle A will get confused as to it's current position in
  380.  *    the file.
  381.  *
  382.  *    I am probably not updating all the right timestamps.  This is
  383.  *    easy to fix... All you have to do is fool with the floppy and
  384.  *    see which datestamps get updated for certain operations.
  385.  */
  386.  
  387.  
  388. /*
  389.  *  Since this code might be called several times in a row without being
  390.  *  unloaded, you CANNOT ASSUME GLOBALS HAVE BEEN ZERO'D!!  This also goes
  391.  *  for any global/static assignments that might be changed by running the
  392.  *  code.
  393.  */
  394.  
  395. #ifdef BEVIRTUAL
  396. int Virtual = 1;            /* default on!!! */
  397. #endif
  398.  
  399. PROC    *DosProc;   /*    Our Process                    */
  400. DEVNODE    *DosNode;   /*    Our DOS node.. created by DOS for us        */
  401. DEVLIST    *DevList;   /*    Device List structure for our volume node   */
  402.  
  403. void    *SysBase;   /*    EXEC library base            */
  404. DOSLIB    *DOSBase;   /*    DOS library base for debug process    */
  405. RAMFILE    RFRoot;     /*    Directory/File structure    (root node) */
  406. LIST    FHBase;     /*    Open Files                */
  407. LIST    LCBase;     /*    Open Locks                */
  408.  
  409. long    TotalBytes; /*    total bytes of data in filesystem    */
  410.  
  411.  
  412.             /*    DEBUGGING            */
  413. PORT *Dbport = 0;    /*    owned by the debug process    */
  414. PORT *Dback = 0;    /*    owned by the DOS device driver    */
  415. short DBDisable;
  416. MSG DummyMsg;        /*    Dummy message that debug proc can use    */
  417.  
  418. /*
  419.  *  Don't call the entry point main().  This way, if you make a mistake
  420.  *  with the compile options you'll get a link error.
  421.  */
  422.  
  423. void
  424. noname()
  425. {
  426.     register PACKET *packet;
  427.     register short   error;
  428.     MSG     *msg;
  429.     ubyte   notdone;
  430.     ubyte   buf[256];
  431.     void    *tmp;
  432.  
  433.     ULONG *wowsers = 0x4;
  434.  
  435. #ifdef BECOLORS
  436.     UWORD *colorptr = 0xdff180;
  437.     UWORD i;
  438.  
  439.     for(i=0;i<300;i++) {
  440.         *colorptr = i;
  441.         };
  442. #endif
  443.  
  444.     /*
  445.      *    Initialize all global variables.  SysBase MUST be initialized before
  446.      *    we can make Exec calls.  AbsExecBase is a library symbol
  447.      *    referencing absolute memory location 4.  The DOS library is opened
  448.      *    for the debug process only.
  449.      */
  450.  
  451.     DBDisable = 1;                /*  Init. globals    */
  452.     Dbport = Dback = NULL;
  453.     TotalBytes = 0;
  454.     SysBase = *(wowsers);  /* AbsExecBase; not anymore AH 91 */
  455.     DOSBase = OpenLibrary("dos.library",0);
  456.     DosProc = FindTask(NULL);
  457.     {
  458.     WaitPort(&DosProc->pr_MsgPort);     /*  Get Startup Packet    */
  459.     msg = GetMsg(&DosProc->pr_MsgPort);
  460.     packet = (PACKET *)msg->mn_Node.ln_Name;
  461.  
  462.     /*
  463.      *  Loading DosNode->dn_Task causes DOS *NOT* to startup a new
  464.      *  instance of the device driver for every reference.    E.G. if
  465.      *  you were writing a CON device you would want this field to
  466.      *  be NULL.
  467.      */
  468.  
  469.     if (DOSBase) {
  470.         DOSINFO *di = BTOC(((ROOTNODE *)DOSBase->dl_Root)->rn_Info);
  471.         register DEVLIST *dl = dosalloc(sizeof(DEVLIST));
  472.  
  473.         DosNode = BTOC(packet->dp_Arg3);
  474.  
  475.         /*
  476.          *    Create Volume node and add to the device list.    This will
  477.          *    cause the WORKBENCH to recognize us as a disk.    If we don't
  478.          *    create a Volume node, Wb will not recognize us.  However,
  479.          *    we are a RAM: disk, Volume node or not.
  480.          */
  481.  
  482.         DevList = dl;
  483.         dl->dl_Type = DLT_VOLUME;
  484.         dl->dl_Task = &DosProc->pr_MsgPort;
  485.         dl->dl_DiskType = ID_DOS_DISK;
  486.         dl->dl_Name = (void *)DosNode->dn_Name;
  487.         dl->dl_Next = di->di_DevInfo;
  488.         di->di_DevInfo = (long)CTOB(dl);
  489.  
  490.         /*
  491.          *    Set dn_Task field which tells DOS not to startup a new
  492.          *    process on every reference.
  493.          */
  494.  
  495.         DosNode->dn_Task = &DosProc->pr_MsgPort;
  496.         packet->dp_Res1 = DOS_TRUE;
  497.         packet->dp_Res2 = 0;
  498.     } else {                /*    couldn't open dos.library   */
  499.         packet->dp_Res1 = DOS_FALSE;
  500.         returnpacket(packet);
  501.         return;                /*    exit process            */
  502.     }
  503.     returnpacket(packet);
  504.     }
  505.  
  506.     /*
  507.      *    Initialize debugging code
  508.      */
  509.  
  510.     if(!DBDisable)dbinit();
  511.  
  512.     /*    Initialize  RAM disk    */
  513.  
  514.     {
  515.     ubyte *ptr = BTOC(DosNode->dn_Name);
  516.     short len = *ptr;
  517.  
  518.     NewList(&FHBase);                /*    more globals    */
  519.     NewList(&LCBase);
  520.     bzero(&RFRoot,sizeof(RFRoot));
  521.     RFRoot.type = FILE_DIR;             /*    root directory    */
  522.     DateStamp(&RFRoot.date);            /*    datestamp    */
  523.     NewList(&RFRoot.list);                /*    sub dirs    */
  524.     RFRoot.name = AllocMem(len+1, MEMF_PUBLIC); /*    Root NAME    */
  525.     bmov(ptr+1,RFRoot.name,len);
  526.     RFRoot.name[len] = 0;
  527.     dbprintf("ROOT NAME: %ld '%s'\n", len, RFRoot.name);
  528.     }
  529.  
  530.     /*
  531.      *    Here begins the endless loop, waiting for requests over our
  532.      *    message port and executing them.  Since requests are sent over
  533.      *    our message port, this precludes being able to call DOS functions
  534.      *    ourselves (that is why the debugging routines are a separate process)
  535.      */
  536.  
  537. top:
  538.     for (notdone = 1; notdone;) {
  539.     WaitPort(&DosProc->pr_MsgPort);
  540.  
  541. #ifdef BECOLORS
  542.     for(i=0;i<300;i++) {
  543.         *colorptr = i;
  544.         };
  545. #endif
  546.  
  547.     while (msg = GetMsg(&DosProc->pr_MsgPort)) {
  548.  
  549.         register ubyte *ptr;
  550.  
  551. #ifdef BECOLORS
  552.     for(i=0;i<300;i++) {
  553.         *colorptr = i;
  554.         };
  555. #endif
  556.  
  557.  
  558.         packet = (PACKET *)msg->mn_Node.ln_Name;
  559.         packet->dp_Res1 = DOS_TRUE;
  560.         packet->dp_Res2 = 0;
  561.         error = 0;
  562.         dbprintf("Packet: %3ld %08lx %08lx %08lx %10s ",
  563.         packet->dp_Type,
  564.         packet->dp_Arg1, packet->dp_Arg2,
  565.         packet->dp_Arg3,
  566.         typetostr(packet->dp_Type)
  567.         );
  568.  
  569.  
  570. /*#ifdef BEDEVICE*/
  571.  
  572.         switch(packet->dp_Type) {
  573.         case ACTION_DIE:        /*    attempt to die?             */
  574.         notdone = 0;        /*    try to die                */
  575.         break;
  576.         case ACTION_OPENRW:     /*    FileHandle,Lock,Name        Bool    */
  577.         case ACTION_OPENOLD:    /*    FileHandle,Lock,Name        Bool    */
  578.         case ACTION_OPENNEW:    /*    FileHandle,Lock,Name        Bool    */
  579.         {
  580.             register RAMFILE *ramfile;
  581.             RAMFILE *parentdir = getlockfile(packet->dp_Arg2); /* passive AH */
  582.             char    *ptr;
  583.  
  584. #ifdef BEVIRTUAL
  585.             ulong *virtual_device = 0;
  586.             ulong *virtual_fh = 0;
  587.             int    VirtualOpen = 0;
  588. #endif
  589.             btos(packet->dp_Arg3,buf);
  590.             dbprintf("'%s' ", buf);
  591.  
  592.             if (strcmp(buf,"debugoff") == 0)
  593.             { DBDisable = 1; dbuninit(); }
  594.  
  595.             if (strcmp(buf,"debugon") == 0)
  596.             { DBDisable = 0; dbinit(); }
  597.  
  598. #ifdef BEVIRTUAL
  599.             if (strcmp(buf,"virtualon") == 0)    /* debugging */
  600.             {
  601.             dbprintf("Virtual is on\n");
  602.             Virtual = 1;
  603.             }
  604.             if (strcmp(buf,"virtualoff") == 0)
  605.             {
  606.             dbprintf("Virtual is off\n");
  607.             Virtual = 0;
  608.             }
  609. #endif
  610.  
  611. /* is found? */
  612.             if (ramfile = searchpath(&parentdir,buf,&ptr))
  613.             {
  614.             if (ramfile->type == FILE_DIR)
  615.                { error=ERROR_OBJECT_WRONG_TYPE; goto openbreak;}
  616.             if (ramfile->locks < 0)
  617.                { error = ERROR_OBJECT_IN_USE; goto openbreak;}
  618.  
  619.  
  620.             if (packet->dp_Type == ACTION_OPENOLD)
  621.             {
  622.                 ++ramfile->locks;  /* fall thru to last bundle */
  623. #ifdef BEVIRTUAL
  624.             /*
  625.                 this routine may abort rest of read attempt
  626.                 note that i've checked above code to make
  627.                 sure that nothing was initialized...so its
  628.                 ok to just "step out" as it were AH Jan2291
  629.             */
  630.  
  631.             if (Virtual)
  632.             {
  633.             UBYTE    mtemp[VIBLEN+512];
  634.             DEVNODE    *MyDevNode;
  635.             /*VIB    *vib;*/
  636.             int    len;
  637.             len = myreadsome(mtemp,GetHead(&(ramfile->list)),VIBLEN+512);
  638.  
  639.             if(!len)
  640.             {
  641.             dbprintf("not virtual file, treating as normal\n");
  642.             goto BENORMAL;
  643.             }
  644.  
  645.             dbprintf("virtual: name to find is %s\n",mtemp+VIBLEN);
  646.  
  647.             if(!(MyDevNode = FindHandler(mtemp+VIBLEN,DOSBase,mtemp+VIBLEN-20)))  /* and key */
  648.                 {
  649.  
  650.  
  651.                 /* ask user to insert disk please */
  652.                 /* if user cancels then say: */
  653.                 /* wait for reply, or search again myself */
  654.                 /* if user does insert I would like to lock it */
  655.  
  656.  
  657.                 dbprintf("device %s not found\n",mtemp+VIBLEN);
  658.                 error = ERROR_OBJECT_NOT_FOUND;
  659.                 --ramfile->locks;
  660.                 goto openbreak;
  661.                 }
  662.                 else
  663.                 {
  664.                 PACKET    copypacket;
  665.  
  666. /* gee i really hope that "buffer" is longword aligned!!!! */
  667.  
  668.                 UBYTE    buffer[512];
  669.  
  670.                 dbprintf("device %s was found %lx\n",mtemp+VIBLEN,MyDevNode->dn_Task);
  671.                 virtual_device = MyDevNode->dn_Task;
  672.  
  673. /*
  674. arg1 = filehandle (to fill)
  675. arg2 = lock (i'll zero this cause there is no parent - i pass entire path!)
  676. arg3 = name (to find) [as a BSTR!]
  677.  */
  678.                 bmov(packet,©packet,sizeof(PACKET));
  679.                 /* copypacket.dp_Arg1 = packet->dp_Arg1...*/
  680.  
  681.                 copypacket.dp_Arg2 = 0;    /* no parent lock! */
  682.  
  683.                 buffer[0] = strlen(mtemp+VIBLEN);
  684.                 strncpy(&(buffer[1]),mtemp+VIBLEN,512-2);
  685.                 copypacket.dp_Arg3 = CTOB(&(buffer[0]));
  686.  
  687.                 if(!(sendpacket(©packet,virtual_device)))
  688.                     {
  689.                     error = ERROR_OBJECT_NOT_FOUND;
  690.                     --ramfile->locks;
  691.                     goto openbreak;
  692.                     }
  693.  
  694.     dbprintf("001: packet sent!\n");
  695.  
  696.                 if(!copypacket.dp_Res1)
  697.                     {
  698.                     error = copypacket.dp_Res2;
  699.                     --ramfile->locks;
  700.                     goto openbreak;
  701.                     }
  702.     dbprintf("002: no error\n");
  703.  
  704.                 /* get and stash the real file handle */
  705.                 virtual_fh = ((FH *)BTOC(packet->dp_Arg1))->fh_Arg1;
  706.  
  707.     dbprintf("file handle is %ld\n",virtual_fh);
  708.  
  709. /*
  710. i call other device, it takes over fh->arg1
  711. i copy fh->arg1 away (may check if 0??? (no should leave same)
  712. i call vir, it takes over fh->arg1 (again)
  713.  */
  714.                 VirtualOpen = 1;
  715.  
  716.  
  717.  /*
  718. open
  719.     - copy the packet (or make a packet)
  720.     - set FileHandle to packet->arg1 (FileHandle)  (in copy also)
  721.     - replace name field of packet (packet->arg3)  (in copy only)
  722.     - set lock to 0                       (in copy only)
  723.     - submit packet to device
  724.     - wait for reply
  725.     - if failed then error = its error, goto openbreak;
  726.     - save for a moment DeviceID & FileHandle, set flag *special*
  727.     - at bottom of open: if *special* set then copy DeviceID/FileHandle in
  728.       (just override parts of MYFH because it shouldn't be used outside
  729.        of READ/WRITE [ SEEK/CLOSE ] and if a file handle is in virtual
  730.        mode it stays that way, regardless of if the handler is in
  731.        virtual mode or not.
  732.  
  733.     *** general; we should think about the visibility of the virtual
  734.         flag, and if it conflicts with re-entrant nature of these
  735.         routines -> i think it does?)
  736.         in which case we should have special packets instead
  737.  */
  738.  
  739.                 }
  740.             } /* endif virtual */
  741. BENORMAL:
  742. #endif
  743.             goto success;
  744.             }
  745.             /* end of open_old */
  746.  
  747.  
  748.  
  749.             else  /* packet request is NOT OPEN OLD */
  750.             {
  751. /* shared read only? */
  752.                 if (ramfile->locks > 0)
  753.                 {
  754.                 error = ERROR_OBJECT_IN_USE;
  755.                 }
  756.                 else
  757.                 {
  758.                 /* new open overtop old file */
  759.                 if (packet->dp_Type == ACTION_OPENNEW) {
  760.                     freedata(ramfile);
  761.                     ramfile->protection = 0;
  762.                     }
  763.                 --ramfile->locks;
  764.                     }
  765.             }
  766.             }
  767.             else  /* file is not found */
  768.             {
  769.             if (!parentdir) {
  770.                 error = ERROR_INVALID_COMPONENT_NAME;
  771.                 goto openbreak;
  772.                 }
  773.             if (packet->dp_Type == ACTION_OPENNEW) {
  774.                 ramfile = createramfile(parentdir, FILE_FILE, ptr);
  775.                 --ramfile->locks;
  776.                 } else
  777.                   {  error = ERROR_OBJECT_NOT_FOUND; }
  778.             }
  779.  
  780.             /* open new and open old success hit here */
  781.  
  782. success:
  783.  
  784. /*
  785.     OPEN_NEW was passed a "FileHandle"; in the file handle there is
  786.     a slot for matt to stick in his "myfh"; which he then does; when we
  787.     want to patch the requests on we will pass the supplied file handle
  788.     onto the next device, and then swap its sub_arg with ours, such that
  789.     we can handle any further requests....swapping as needed.
  790.  */
  791.             if (!error)
  792.             {
  793.             register MYFH *mfh = AllocMem(sizeof(MYFH), MEMF_PUBLIC|MEMF_CLEAR);
  794.             ((FH *)BTOC(packet->dp_Arg1))->fh_Arg1 = (long)mfh;
  795.             mfh->file = ramfile;
  796.             mfh->fentry = GetHead(&ramfile->list);
  797.  
  798. #ifdef BEVIRTUAL
  799.             if(!VirtualOpen)
  800.             {
  801.                 mfh->device = 0;    /* Virtual AHJan2391 */
  802.                 mfh->devfh = 0;
  803.             }
  804.             else
  805.             {
  806.                 mfh->device = virtual_device;
  807.                 mfh->devfh  = virtual_fh;
  808.             }
  809. #endif
  810.             AddHead(&FHBase,mfh);
  811.             }
  812.         }
  813. openbreak:
  814.         if (!GetHead(&FHBase) && !GetHead(&LCBase))
  815.             notdone = 0;
  816.         break;
  817.         case ACTION_READ:        /*     FHArg1,CPTRBuffer,Length   ActLength  */
  818.         {
  819.             register MYFH   *mfh = (MYFH *)packet->dp_Arg1;
  820.             register FENTRY *fen = mfh->fentry;
  821.             register ubyte  *ptr = (ubyte *)packet->dp_Arg2;
  822.             register long   left = packet->dp_Arg3;
  823.             register long   scr;
  824.  
  825.         if(andycode("read",mfh,packet))break;
  826.  
  827.             while (left && fen) {
  828.             scr = fen->bytes - mfh->offset;
  829.             if (left < scr) {
  830.                 bmov(fen->buf + mfh->offset, ptr, left);
  831.                 mfh->offset += left;
  832.                 left = 0;
  833.             } else {
  834.                 bmov(fen->buf + mfh->offset, ptr, scr);
  835.                 left -= scr;
  836.                 ptr += scr;
  837.                 mfh->base += fen->bytes;
  838.                 mfh->offset = 0;
  839.                 fen = NextNode(fen);
  840.             }
  841.             }
  842.             mfh->fentry = fen;
  843.             packet->dp_Res1 = packet->dp_Arg3 - left;
  844.         }
  845.         break;
  846.         case ACTION_WRITE:        /*     FHArg1,CPTRBuffer,Length   ActLength  */
  847.         {
  848.             register MYFH   *mfh = (MYFH *)packet->dp_Arg1;
  849.             register FENTRY *fen = (FENTRY *)mfh->fentry;
  850.             ubyte  *ptr = (ubyte *)packet->dp_Arg2;
  851.             long   left = packet->dp_Arg3;
  852.             long   scr;
  853.  
  854.         if(andycode("write",mfh,packet)) break;
  855.  
  856.             /*
  857.              *    Doesn't work right if multiple readers/appenders.
  858.              */
  859.  
  860.             while (left) {
  861.             if (fen) {
  862.                 dbprintf("FEN: %ld  left: %ld\n", fen->bytes, left);
  863.                 scr = fen->bytes - mfh->offset;
  864.                 if (left < scr) {
  865.                 if (fen->bytes < mfh->offset + left)
  866.                     dbprintf("PANIC! AWR0\n");
  867.                 else
  868.                     bmov(ptr, fen->buf + mfh->offset, left);
  869.                 mfh->offset += left;
  870.                 left = 0;
  871.                 } else {
  872.                 if (fen->bytes < mfh->offset + scr)
  873.                     dbprintf("PANIC! AWR1\n");
  874.                 else
  875.                     bmov(ptr, fen->buf + mfh->offset, scr);
  876.                 ptr += scr;
  877.                 left -= scr;
  878.                 mfh->base += fen->bytes;
  879.                 mfh->offset = 0;
  880.                 fen = NextNode(fen);
  881.                 }
  882.             } else {
  883.                 fen = AllocMem(sizeof(FENTRY), MEMF_PUBLIC);
  884.                 if (fen->buf = AllocMem(left, MEMF_PUBLIC)) {
  885.                 fen->bytes = left;
  886.                 mfh->file->bytes += left;
  887.                 mfh->base  += left;
  888.                 mfh->offset = 0;
  889.                 TotalBytes += left;
  890.                 AddTail(&mfh->file->list, fen);
  891.                 dbprintf("NEWFEN: (%ld)\n", fen->bytes);
  892.                 bmov(ptr, fen->buf, left);
  893.                 left = 0;
  894.                 } else {
  895.                 FreeMem(fen, sizeof(FENTRY));
  896.                 dbprintf("NEWFEN: ****** Unable to allocate buffer %ld\n", left);
  897.                 mfh->offset = 0;
  898.                 break;
  899.                 }
  900.                 fen = NULL;     /*    cause append    */
  901.             }
  902.             }
  903.             packet->dp_Res1 = packet->dp_Arg3 - left;
  904.             mfh->fentry = fen;
  905.         }
  906.         break;
  907.         case ACTION_CLOSE:        /*     FHArg1             Bool:TRUE  */
  908.         {
  909.             register MYFH   *mfh = (MYFH *)packet->dp_Arg1;
  910.             register RAMFILE *file = mfh->file;
  911.  
  912.         andycode("close",mfh,packet);
  913.  
  914.             Remove(mfh);
  915.             FreeMem(mfh,sizeof(*mfh));
  916.             if (--file->locks < 0)
  917.             file->locks = 0;
  918.         }
  919.         if (!GetHead(&FHBase) && !GetHead(&LCBase))
  920.             notdone = 0;
  921.         break;
  922.         case ACTION_SEEK:        /*     FHArg1,Position,Mode        OldPosition*/
  923.         {
  924.             register MYFH *mfh = (MYFH *)packet->dp_Arg1;
  925.             register FENTRY *fen;
  926.             register long absseek;
  927.  
  928.         if(andycode("seek",mfh,packet))break;
  929.  
  930.             packet->dp_Res1 = mfh->base + mfh->offset;
  931.             absseek = packet->dp_Arg2;
  932.             if (packet->dp_Arg3 == 0)
  933.             absseek += mfh->base + mfh->offset;
  934.             if (packet->dp_Arg3 == 1)
  935.             absseek = mfh->file->bytes + absseek;
  936.             if (absseek < 0 || absseek > mfh->file->bytes) {
  937.             error = ERROR_SEEK_ERROR;
  938.             break;
  939.             }
  940.             mfh->base = mfh->offset = 0;
  941.  
  942.             /*
  943.              *    Stupid way to do it but....
  944.              */
  945.  
  946.             for (fen = GetHead(&mfh->file->list); fen; fen = NextNode(fen)) {
  947.             if (mfh->base + fen->bytes > absseek) {
  948.                 mfh->offset = absseek - mfh->base;
  949.                 break;
  950.             }
  951.             mfh->base += fen->bytes;
  952.             }
  953.             mfh->fentry = fen;
  954.         }
  955.         break;
  956.         /*
  957.          *    This implementation sucks.  The right way to do it is with
  958.          *    a hash table.  The directory must be searched for the file
  959.          *    name, then the next entry retrieved.  If the next entry is
  960.          *    NULL there are no more entries.  If the filename could not
  961.          *    be found we return the first entry, if any.
  962.          *
  963.          *    You can't simply keep a pointer around to the next node
  964.          *    because it can be moved or removed at any time.
  965.          */
  966.  
  967.         case ACTION_EXAMINE_NEXT: /*   Lock,Fib              Bool     */
  968.         {
  969.             register FIB *fib = BTOC(packet->dp_Arg2);
  970.             register RAMFILE *dir = getlockfile(packet->dp_Arg1);
  971.             register RAMFILE *file;
  972.             long    *blah;
  973.  
  974.             if (dir->type == FILE_FILE) {
  975.             error = ERROR_OBJECT_WRONG_TYPE;
  976.             break;
  977.             }
  978.             file = GetHead(&dir->list);
  979.  
  980.             blah = &(fib->fib_Comment[68]);
  981.             fib->fib_Comment[67] = 0;
  982.  
  983. /*        if(fib->fib_DiskKey) { */
  984.             if (*blah) {
  985.             register int len = *(ubyte *)fib->fib_FileName;
  986.             for (; file; file = NextNode(file)) {
  987.                 if (strlen(file->name) == len && nccmp(file->name, fib->fib_FileName+1, len))
  988.                 break;
  989.             }
  990.             if (file)
  991.                 file = NextNode(file);
  992.             else
  993.                 file = GetHead(&dir->list);
  994.             }
  995.             *blah = 1; 
  996. /*            fib->fib_DiskKey = 1; */
  997.             error = -1;
  998.             if (!(tmp=file)) {
  999.             error = ERROR_NO_MORE_ENTRIES;
  1000.             break;
  1001.             }
  1002.         }
  1003.         /*  fall through    */
  1004.         case ACTION_EXAMINE_OBJECT: /*   Lock,Fib            Bool       */
  1005.         {
  1006.             register FIB *fib;
  1007.             register RAMFILE *file;
  1008.             register RAMFILE *dummy;
  1009.  
  1010.             fib = BTOC(packet->dp_Arg2);
  1011.             if (error) {
  1012.             file = tmp;    /*  fall through from above */
  1013.             } else {
  1014.             file = getlockfile(packet->dp_Arg1);
  1015.  
  1016.             fib->fib_Comment[67] = 0;
  1017.             fib->fib_Comment[68] = 0;
  1018.             fib->fib_Comment[69] = 0;
  1019.             fib->fib_Comment[70] = 0;
  1020.             fib->fib_Comment[71] = 0;
  1021.  
  1022. /*            fib->fib_DiskKey = 0; */
  1023.             }
  1024.             error = 0;
  1025.             fib->fib_DirEntryType = file->type;
  1026.             strcpy(fib->fib_FileName+1, file->name);
  1027.             fib->fib_FileName[0] = strlen(file->name);
  1028.             fib->fib_Protection = file->protection;
  1029.             fib->fib_EntryType = file->type;
  1030.         {
  1031.             long    *blah;
  1032.             blah = (long *)(&(fib->fib_DiskKey));
  1033.             *blah = (long *)file;
  1034.                 /* every file must have a unique KEY!!! */
  1035.                 /* AmigaDOS and I both use this scheme to
  1036.                    make sure 2 files are not same instance */
  1037.         }
  1038.             fib->fib_Size = file->bytes;
  1039.             fib->fib_NumBlocks = (fib->fib_Size / 512);
  1040.             fib->fib_Date = file->date;
  1041.             if (file->comment) {
  1042. /*!!AH!*/        strncpy(fib->fib_Comment+1, file->comment,65);
  1043.             fib->fib_Comment[0] = strlen(file->comment);
  1044.             } else {
  1045.             fib->fib_Comment[0] = 0;
  1046.             }
  1047.  
  1048. #ifdef BEVIRTUAL
  1049.         if (Virtual && file->type < 0) {
  1050.             VIB vib;
  1051.             int x;  long *myptr;
  1052.             x = myreadsome(&vib,GetHead(&(file->list)),VIBLEN);
  1053.  
  1054.             dbprintf("coolo %ld %ld\n",x,VIBLEN);
  1055.  
  1056.             if(!x)    {
  1057.                 dbprintf("examine: file is not virtual");
  1058.                 goto JUSTNORMAL;
  1059.                 }
  1060.  
  1061.             fib->fib_Size = vib.Size;
  1062.             fib->fib_NumBlocks = (fib->fib_Size / 512);
  1063.  
  1064.     /* information that must be returned to the coalesce utility,
  1065.        external to the handler...just a checksum... */
  1066.  
  1067.             fib->fib_Comment[67] = 0;
  1068.             myptr = &(fib->fib_Comment[72]);
  1069.             *(myptr) = VIRT;
  1070.             *(myptr+1) = vib.CheckSum;
  1071.  
  1072.  
  1073.             }
  1074. JUSTNORMAL:
  1075. #endif
  1076.         }
  1077.         break;
  1078.         case ACTION_INFO:        /*    Lock, InfoData      Bool:TRUE    */
  1079.         tmp = BTOC(packet->dp_Arg2);
  1080.         error = -1;
  1081.         /*  fall through    */
  1082.         case ACTION_DISK_INFO:  /*    InfoData      Bool:TRUE    */
  1083.         {
  1084.             register INFODATA *id;
  1085.  
  1086.             /*
  1087.              *    Note:    id_NumBlocks is never 0, but only to get
  1088.              *    around a bug I found in my shell (where I divide
  1089.              *    by id_NumBlocks).  Other programs probably break
  1090.              *    as well.
  1091.              */
  1092.  
  1093.             (error) ? (id = tmp) : (id = BTOC(packet->dp_Arg1));
  1094.             error = 0;
  1095.             bzero(id, sizeof(*id));
  1096.             id->id_DiskState = ID_VALIDATED;
  1097.             id->id_NumBlocks     = (TotalBytes >> 9) + 1;
  1098.             id->id_NumBlocksUsed = (TotalBytes >> 9) + 1;
  1099.             id->id_BytesPerBlock = 512;
  1100.             id->id_DiskType = ID_DOS_DISK;
  1101.             id->id_VolumeNode = (long)CTOB(DosNode);
  1102.             id->id_InUse = (long)GetHead(&LCBase);
  1103.         }
  1104.         break;
  1105.         case ACTION_PARENT:     /*     Lock                ParentLock */
  1106.         {
  1107.             register RAMFILE *file = getlockfile(packet->dp_Arg1);
  1108.             if (file->type == FILE_FILE) {
  1109.             error = ERROR_OBJECT_NOT_FOUND;
  1110.             break;
  1111.             }
  1112.             if (file->locks < 0) {
  1113.             error = ERROR_OBJECT_IN_USE;
  1114.             break;
  1115.             }
  1116.             if (file->parent)
  1117.             packet->dp_Res1 = (long)CTOB(ramlock(file->parent, ACCESS_READ));
  1118.             else
  1119.             error = ERROR_OBJECT_NOT_FOUND;
  1120.         }
  1121.         break;
  1122.         case ACTION_DELETE_OBJECT: /*Lock,Name            Bool       */
  1123.         {
  1124.             RAMFILE *parentdir = getlockfile(packet->dp_Arg1);
  1125.             RAMFILE *ramfile;
  1126.  
  1127.             btos(packet->dp_Arg2, buf);
  1128.             if (ramfile = searchpath(&parentdir,buf,NULL)) {
  1129.             if (ramfile->locks || ramfile == &RFRoot) {
  1130.                 error = ERROR_OBJECT_IN_USE;
  1131.                 break;
  1132.             }
  1133.             if (ramfile->type == FILE_DIR) {
  1134.                 if (GetHead(&ramfile->list))
  1135.                 error = ERROR_DIRECTORY_NOT_EMPTY;
  1136.             } else {
  1137.                 freedata(ramfile);
  1138.             }
  1139.             if (!error) {
  1140.                 freeramfile(ramfile);
  1141.                 DateStamp(&parentdir->date);
  1142.             }
  1143.             } else {
  1144.             if (!parentdir)
  1145.                 error = ERROR_INVALID_COMPONENT_NAME;
  1146.             else
  1147.                 error = ERROR_OBJECT_NOT_FOUND;
  1148.             }
  1149.         }
  1150.         if (!GetHead(&FHBase) && !GetHead(&LCBase))
  1151.             notdone = 0;
  1152.         break;
  1153.         case ACTION_CREATE_DIR: /*     Lock,Name            Lock       */
  1154.         {
  1155.             RAMFILE *parentdir = getlockfile(packet->dp_Arg1);
  1156.             RAMFILE *ramfile;
  1157.             char *ptr;
  1158.  
  1159.             btos(packet->dp_Arg2, buf);
  1160.             if (ramfile = searchpath(&parentdir,buf,&ptr)) {
  1161.             error = ERROR_OBJECT_EXISTS;
  1162.             break;
  1163.             }
  1164.             if (!parentdir) {
  1165.             error = ERROR_INVALID_COMPONENT_NAME;
  1166.             break;
  1167.             }
  1168.             ramfile = createramfile(parentdir, FILE_DIR, ptr);
  1169.             packet->dp_Res1 = (long)CTOB(ramlock(ramfile, ACCESS_WRITE));
  1170.         }
  1171.         break;
  1172.         case ACTION_LOCATE_OBJECT:    /*   Lock,Name,Mode        Lock       */
  1173.         {
  1174.             RAMFILE *parentdir = getlockfile(packet->dp_Arg1);
  1175.             RAMFILE *ramfile;
  1176.  
  1177.             btos(packet->dp_Arg2, buf);
  1178.             dbprintf("'%s' %ld ", buf, packet->dp_Arg3);
  1179.             if (ramfile = searchpath(&parentdir,buf,NULL)) {
  1180.             if (ramfile->locks < 0 || (ramfile->locks && packet->dp_Arg3 == ACCESS_WRITE)) {
  1181.                 error = ERROR_OBJECT_IN_USE;
  1182.                 break;
  1183.             }
  1184.             packet->dp_Res1 = (long)CTOB(ramlock(ramfile, packet->dp_Arg3));
  1185.             } else {
  1186.             if (!parentdir)
  1187.                 error = ERROR_INVALID_COMPONENT_NAME;
  1188.             else
  1189.                 error = ERROR_OBJECT_NOT_FOUND;
  1190.             }
  1191.         }
  1192.         break;
  1193.         case ACTION_COPY_DIR:   /*     Lock,                Lock       */
  1194.         {
  1195.             register RAMFILE *ramfile = getlockfile(packet->dp_Arg1);
  1196.             if (ramfile->locks < 0)
  1197.             error = ERROR_OBJECT_IN_USE;
  1198.             else
  1199.             packet->dp_Res1 = (long)CTOB(ramlock(ramfile, ACCESS_READ));
  1200.         }
  1201.         break;
  1202.         case ACTION_FREE_LOCK:  /*     Lock,                Bool       */
  1203.         if (packet->dp_Arg1);
  1204.             ramunlock(BTOC(packet->dp_Arg1));
  1205.         if (!GetHead(&FHBase) && !GetHead(&LCBase))
  1206.             notdone = 0;
  1207.         break;
  1208.         case ACTION_SET_PROTECT:/*     -,Lock,Name,Mask       Bool       */
  1209.         {
  1210.             register RAMFILE *ramfile;
  1211.             RAMFILE *parentdir = getlockfile(packet->dp_Arg2);
  1212.             char *ptr;
  1213.  
  1214.             btos(packet->dp_Arg3, buf);
  1215.             if (ramfile = searchpath(&parentdir,buf,&ptr)) {
  1216.             ramfile->protection = packet->dp_Arg4;
  1217.             } else {
  1218.             if (parentdir)
  1219.                 error = ERROR_OBJECT_NOT_FOUND;
  1220.             else
  1221.                 error = ERROR_INVALID_COMPONENT_NAME;
  1222.             }
  1223.         }
  1224.         break;
  1225.         case ACTION_SET_COMMENT:/*     -,Lock,Name,Comment       Bool       */
  1226.         {
  1227.             register RAMFILE *ramfile;
  1228.             RAMFILE *parentdir = getlockfile(packet->dp_Arg2);
  1229.             char *ptr;
  1230.  
  1231.             btos(packet->dp_Arg3, buf);
  1232.             if (ramfile = searchpath(&parentdir,buf,&ptr)) {
  1233.             btos(packet->dp_Arg4, buf);
  1234.             if (ramfile->comment)
  1235.                 FreeMem(ramfile->comment,strlen(ramfile->comment)+1);
  1236.             ramfile->comment = AllocMem(strlen(buf)+1, MEMF_PUBLIC);
  1237.             strcpy(ramfile->comment, buf);
  1238.             } else {
  1239.             if (parentdir)
  1240.                 error = ERROR_OBJECT_NOT_FOUND;
  1241.             else
  1242.                 error = ERROR_INVALID_COMPONENT_NAME;
  1243.             }
  1244.         }
  1245.         break;
  1246.         case ACTION_RENAME_OBJECT:/* SLock,SName,DLock,DName    Bool       */
  1247.         {
  1248.             register RAMFILE *file1;
  1249.             RAMFILE *sourcedir = getlockfile(packet->dp_Arg1);
  1250.             RAMFILE *destdir   = getlockfile(packet->dp_Arg3);
  1251.             char *ptr;
  1252.  
  1253.             btos(packet->dp_Arg2,buf);
  1254.             dbprintf("\nRENAME '%s' (%ld)  ", buf, strlen(buf));
  1255.             if (file1 = searchpath(&sourcedir,buf,NULL)) {
  1256.             btos(packet->dp_Arg4,buf);
  1257.             dbprintf("TO '%s' (%ld)", buf, strlen(buf));
  1258.             if (searchpath(&destdir,buf,&ptr)) {
  1259.                 error = ERROR_OBJECT_EXISTS;
  1260.             } else {
  1261.                 if (destdir) {
  1262.                 if (file1 == destdir) { /* moving inside self */
  1263.                     error = ERROR_OBJECT_IN_USE;
  1264.                     break;
  1265.                 }
  1266.                 dbprintf("REN '%s' %ld", ptr, strlen(ptr));
  1267.                 DateStamp(&sourcedir->date);
  1268.                 DateStamp(&destdir->date);
  1269.                 /*FreeMem(file1->name, strlen(file1->name)+1);*/
  1270.                 Remove(file1);
  1271.                 file1->name = AllocMem(strlen(ptr)+1,MEMF_PUBLIC);
  1272.                 file1->parent = destdir;
  1273.                 strcpy(file1->name, ptr);
  1274.                 AddHead(&destdir->list, file1);
  1275.                 } else {
  1276.                 error = ERROR_INVALID_COMPONENT_NAME;
  1277.                 }
  1278.             }
  1279.             } else {
  1280.             if (sourcedir)
  1281.                 error = ERROR_OBJECT_NOT_FOUND;
  1282.             else
  1283.                 error = ERROR_INVALID_COMPONENT_NAME;
  1284.             }
  1285.         }
  1286.         break;
  1287.         /*
  1288.          *    A few other packet types which we do not support
  1289.          */
  1290.         case ACTION_INHIBIT:    /*     Bool                Bool       */
  1291.         /*  Return success for the hell of it    */
  1292.         break;
  1293.         case ACTION_RENAME_DISK:/*     BSTR:NewName            Bool       */
  1294.         case ACTION_MORECACHE:  /*     #BufsToAdd            Bool       */
  1295.         case ACTION_WAIT_CHAR:  /*     Timeout, ticks         Bool       */
  1296.         case ACTION_FLUSH:        /*     writeout bufs, disk motor off           */
  1297.         case ACTION_RAWMODE:    /*     Bool(-1:RAW 0:CON)        OldState   */
  1298.         default:
  1299.         error = ERROR_ACTION_NOT_KNOWN;
  1300.         break;
  1301.         }
  1302. /*#endif*/
  1303.  
  1304.         if (packet) {
  1305.         if (error) {
  1306.             dbprintf("ERR=%ld\n", error);
  1307.             packet->dp_Res1 = DOS_FALSE;
  1308.             packet->dp_Res2 = error;
  1309.         } else {
  1310.             dbprintf("RES=%06lx\n", packet->dp_Res1);
  1311.         }
  1312.  
  1313. /* #ifdef BEDEVICE */
  1314.         returnpacket(packet);
  1315. /*#endif */
  1316.         }
  1317. forgotten:
  1318.     }
  1319.     }
  1320.     dbprintf("Can we remove ourselves? ");
  1321.     Delay(50);        /*    I wanna even see the debug message! */
  1322.     Forbid();
  1323.     if (packetsqueued(DosProc) || GetHead(&FHBase) || GetHead(&LCBase)
  1324.       || GetHead(&RFRoot.list)) {
  1325.     Permit();
  1326.     dbprintf(" ..  not yet!\n");
  1327.     goto top;        /*  sorry... can't exit     */
  1328.     }
  1329.  
  1330.     /*
  1331.      *    Causes a new process to be created on next reference
  1332.      */
  1333.  
  1334.     DosNode->dn_Task = FALSE;
  1335.  
  1336.     /*
  1337.      *    Remove Volume entry.  Since DOS uses singly linked lists, we
  1338.      *    must (ugg) search it manually to find the link before our
  1339.      *    Volume entry.
  1340.      */
  1341.  
  1342.     {
  1343.     DOSINFO *di = BTOC(((ROOTNODE *)DOSBase->dl_Root)->rn_Info);
  1344.     register DEVLIST *dl;
  1345.     register void *dlp;
  1346.  
  1347.     dlp = &di->di_DevInfo;
  1348.     for (dl = BTOC(di->di_DevInfo); dl && dl != DevList; dl = BTOC(dl->dl_Next))
  1349.         dlp = &dl->dl_Next;
  1350.     if (dl == DevList) {
  1351.         *(BPTR *)dlp = dl->dl_Next;
  1352.         dosfree(dl);
  1353.     } else {
  1354.         dbprintf("****PANIC: Unable to find volume node\n");
  1355.     }
  1356.     }
  1357.  
  1358.     /*
  1359.      *    Remove debug process, closedown, fall of the end of the world
  1360.      *    (which is how you kill yourself if a PROCESS.  A TASK would have
  1361.      *    had to RemTask(NULL) itself).
  1362.      */
  1363.  
  1364.     dbuninit();
  1365.     CloseLibrary(DOSBase);
  1366. }
  1367.  
  1368.  
  1369.  
  1370. /*
  1371.     the way this works is as follows:
  1372.  
  1373.     [ page 273 of Amiga Dos Tech Ref Man (lower of the 2 paragraphs) ]
  1374.  
  1375.     there is the idea of a user "FileHandle" - different from "MYFH"
  1376.     when you call _LVORead it takes the user FileHandle and extracts
  1377.     from it FileHandle->Arg1.  Where Arg1 is "MYFH" - in this case
  1378.     as Matt prosaically refers to it "My File Handle".  This is what
  1379.     we receive here.  MYFH was created by our own OPEN command, and
  1380.     thus is our own completely private entity; and all we ever see
  1381.     during the read - actually all we ever see ever.
  1382.  
  1383.     presumably the _LVOOpen command stashes MYFH into the user FileHandle
  1384.     after calling us (on success).
  1385.  
  1386.     anyway this is non obvious and the subtle difference between
  1387.     user-FileHandle and Handler-FileHandle is not delinated whatsoever.
  1388.  
  1389.  
  1390. read/write
  1391.     - (must ignore Virtual on/off flag)
  1392.     - if *special* set only:
  1393.     - extract device id (MYFH->dev), real file handle (MYFH->special)
  1394.     - put real file-handle (MYFH->special) into packet->arg 1
  1395.     - patch packet directly to real device (as per device id)
  1396.     - later may copy packet, but then i have to send it and wait for rep
  1397.  
  1398.  */
  1399.  
  1400.  
  1401. andycode(name,mfh,packet)
  1402. char *name;
  1403. MYFH *mfh;
  1404. PACKET  *packet;
  1405. {
  1406.  
  1407. #ifdef BEVIRTUAL
  1408.             if(mfh->device)
  1409.             {
  1410.             PACKET    copypacket;
  1411.             bmov(packet,©packet,sizeof(PACKET));
  1412.             copypacket.dp_Arg1 = mfh->devfh;
  1413.  dbprintf("accessing %s\n",name);
  1414.             if(!(sendpacket(©packet,mfh->device)))
  1415.                 {
  1416.                 dbprintf("Holy Shit Batman!\n");
  1417.                 }
  1418.              packet->dp_Res1 = copypacket.dp_Res1;
  1419.  dbprintf("accessing done %s\n",name);
  1420.             return(1);
  1421.             }
  1422.             else return(0);
  1423. #else
  1424.     return(0);
  1425. #endif
  1426.  
  1427. }
  1428.  
  1429.  
  1430.  
  1431. /*
  1432.  *  PACKET ROUTINES.    Dos Packets are in a rather strange format as you
  1433.  *  can see by this and how the PACKET structure is extracted in the
  1434.  *  GetMsg() of the main routine.
  1435.  */
  1436.  
  1437. void
  1438. returnpacket(packet)
  1439. register struct DosPacket *packet;
  1440. {
  1441.     register struct Message *mess;
  1442.     register struct MsgPort *replyport;
  1443.  
  1444.     replyport             = packet->dp_Port;
  1445.     mess             = packet->dp_Link;
  1446.     packet->dp_Port         = &DosProc->pr_MsgPort;
  1447.     mess->mn_Node.ln_Name    = (char *)packet;
  1448.     mess->mn_Node.ln_Succ    = NULL;
  1449.     mess->mn_Node.ln_Pred    = NULL;
  1450.     PutMsg(replyport, mess);
  1451. }
  1452.  
  1453. /*
  1454.  *  Are there any packets queued to our device?
  1455.  */
  1456.  
  1457. packetsqueued()
  1458. {
  1459.     return ((void *)DosProc->pr_MsgPort.mp_MsgList.lh_Head !=
  1460.         (void *)&DosProc->pr_MsgPort.mp_MsgList.lh_Tail);
  1461. }
  1462.  
  1463. /*
  1464.  *  DOS MEMORY ROUTINES
  1465.  *
  1466.  *  DOS makes certain assumptions about LOCKS.    A lock must minimally be
  1467.  *  a FileLock structure, with additional private information after the
  1468.  *  FileLock structure.  The longword before the beginning of the structure
  1469.  *  must contain the length of structure + 4.
  1470.  *
  1471.  *  NOTE!!!!! The workbench does not follow the rules and assumes it can
  1472.  *  copy lock structures.  This means that if you want to be workbench
  1473.  *  compatible, your lock structures must be EXACTLY sizeof(struct FileLock).
  1474.  */
  1475.  
  1476. void *
  1477. dosalloc(bytes)
  1478. register ulong bytes;
  1479. {
  1480.     register ulong *ptr;
  1481.  
  1482.     bytes += 4;
  1483.     ptr = AllocMem(bytes, MEMF_PUBLIC|MEMF_CLEAR);
  1484.     *ptr = bytes;
  1485.     return(ptr+1);
  1486. }
  1487.  
  1488. dosfree(ptr)
  1489. register ulong *ptr;
  1490. {
  1491.     --ptr;
  1492.     FreeMem(ptr, *ptr);
  1493. }
  1494.  
  1495. /*
  1496.  *  Convert a BSTR into a normal string.. copying the string into buf.
  1497.  *  I use normal strings for internal storage, and convert back and forth
  1498.  *  when required.
  1499.  */
  1500.  
  1501. void
  1502. btos(bstr,buf)
  1503. ubyte *bstr;
  1504. ubyte *buf;
  1505. {
  1506.     bstr = BTOC(bstr);
  1507.     bmov(bstr+1,buf,*bstr);
  1508.     buf[*bstr] = 0;
  1509. }
  1510.  
  1511. /*
  1512.  *  Some EXEC list handling routines not found in the EXEC library.
  1513.  */
  1514.  
  1515. void *
  1516. NextNode(node)
  1517. NODE *node;
  1518. {
  1519.     node = node->mln_Succ;
  1520.     if (node->mln_Succ == NULL)
  1521.     return(NULL);
  1522.     return(node);
  1523. }
  1524.  
  1525. void *
  1526. GetHead(list)
  1527. LIST *list;
  1528. {
  1529.     if ((void *)list->mlh_Head != (void *)&list->mlh_Tail)
  1530.     return(list->mlh_Head);
  1531.     return(NULL);
  1532. }
  1533.  
  1534. /*
  1535.  *  Compare two names which are at least n characters long each,
  1536.  *  ignoring case.
  1537.  */
  1538.  
  1539. nccmp(p1,p2,n)
  1540. register ubyte *p1, *p2;
  1541. register short n;
  1542. {
  1543.     while (--n >= 0) {
  1544.     if ((p1[n]|0x20) != (p2[n]|0x20))
  1545.         return(0);
  1546.     }
  1547.     return(1);
  1548. }
  1549.  
  1550. /*
  1551.  *  Create a file or directory and link it into it's parent directory.
  1552.  */
  1553.  
  1554. RAMFILE *
  1555. createramfile(parentdir, type, name)
  1556. RAMFILE *parentdir;
  1557. char *name;
  1558. {
  1559.     register RAMFILE *ramfile;
  1560.  
  1561.     ramfile = AllocMem(sizeof(RAMFILE), MEMF_CLEAR|MEMF_PUBLIC);
  1562.     AddTail(&parentdir->list, ramfile);
  1563.     ramfile->parent = parentdir;
  1564.     ramfile->name = AllocMem(strlen(name)+1, MEMF_PUBLIC);
  1565.     strcpy(ramfile->name, name);
  1566.     ramfile->type = type;
  1567.     ramfile->protection = 0;
  1568.     NewList(&ramfile->list);
  1569.     DateStamp(&ramfile->date);
  1570.     DateStamp(&ramfile->parent->date);
  1571.     return(ramfile);
  1572. }
  1573.  
  1574. /*
  1575.  *  Free all data associated with a file
  1576.  */
  1577.  
  1578. void
  1579. freedata(ramfile)
  1580. RAMFILE *ramfile;
  1581. {
  1582.     FENTRY *fen;
  1583.  
  1584.     TotalBytes -= ramfile->bytes;
  1585.     while (fen = RemHead(&ramfile->list)) {
  1586.     dbprintf("FREE FEN: %08lx %08lx %ld\n", fen, fen->buf, fen->bytes);
  1587.     FreeMem(fen->buf, fen->bytes);
  1588.     FreeMem(fen, sizeof(*fen));
  1589.     }
  1590.     ramfile->bytes = 0;
  1591.     DateStamp(&ramfile->date);
  1592.     DateStamp(&ramfile->parent->date);
  1593. }
  1594.  
  1595. /*
  1596.  *  Unlink and remove a file.  Any data associated with the file or
  1597.  *  directory has already been freed up.
  1598.  */
  1599.  
  1600. void
  1601. freeramfile(ramfile)
  1602. RAMFILE *ramfile;
  1603. {
  1604.     Remove(ramfile);        /*  unlink from parent directory    */
  1605.     if (ramfile->name)
  1606.     FreeMem(ramfile->name,strlen(ramfile->name)+1);
  1607.     if (ramfile->comment)
  1608.     FreeMem(ramfile->comment,strlen(ramfile->comment)+1);
  1609.     FreeMem(ramfile,sizeof(*ramfile));
  1610. }
  1611.  
  1612. /*
  1613.  *  The lock function.    The file has already been checked to see if it
  1614.  *  is lockable given the mode.
  1615.  */
  1616.  
  1617. LOCK *
  1618. ramlock(ramfile, mode)
  1619. RAMFILE *ramfile;
  1620. {
  1621.     LOCK *lock = dosalloc(sizeof(LOCK));
  1622.     LOCKLINK *ln;
  1623.  
  1624.     if (mode != ACCESS_WRITE)
  1625.     mode = ACCESS_READ;
  1626.     ln = AllocMem(sizeof(LOCKLINK), MEMF_PUBLIC);
  1627.     AddHead(&LCBase,ln);
  1628.     ln->lock = lock;
  1629.     lock->fl_Link= (long)ln;
  1630.     lock->fl_Key = (long)ramfile;
  1631.     lock->fl_Access = mode;
  1632.     lock->fl_Task = &DosProc->pr_MsgPort;
  1633.     lock->fl_Volume = (BPTR)CTOB(DosNode);
  1634.     if (mode == ACCESS_READ)
  1635.     ++ramfile->locks;
  1636.     else
  1637.     ramfile->locks = -1;
  1638.     return(lock);
  1639. }
  1640.  
  1641. void
  1642. ramunlock(lock)
  1643. LOCK *lock;
  1644. {
  1645.     RAMFILE *file = (RAMFILE *)lock->fl_Key;
  1646.  
  1647.     Remove(lock->fl_Link);            /* unlink from list */
  1648.     FreeMem(lock->fl_Link, sizeof(LOCKLINK));    /* free link node   */
  1649.     if (lock->fl_Access == ACCESS_READ)     /* undo lock effect */
  1650.     --file->locks;
  1651.     else
  1652.     file->locks = 0;
  1653.     dosfree(lock);                /* free lock        */
  1654. }
  1655.  
  1656. /*
  1657.  *  GETLOCKFILE(bptrlock)
  1658.  *
  1659.  *  Return the RAMFILE entry (file or directory) associated with the
  1660.  *  given lock, which is passed as a BPTR.
  1661.  *
  1662.  *  According to the DOS spec, the only way a NULL lock will ever be
  1663.  *  passed to you is if the DosNode->dn_Lock is NULL, but I'm not sure.
  1664.  *  In anycase, If a NULL lock is passed to me I simply assume it means
  1665.  *  the root directory of the RAM disk.
  1666.  */
  1667.  
  1668. RAMFILE *
  1669. getlockfile(lock)
  1670. void *lock;        /*  actually BPTR to LOCK */
  1671. {
  1672.     register LOCK *rl = BTOC(lock);
  1673.  
  1674.     if (rl)
  1675.     return((RAMFILE *)rl->fl_Key);
  1676.     return(&RFRoot);
  1677. }
  1678.  
  1679. /*
  1680.  *  Search the specified path beginning at the specified directory.
  1681.  *  The directory pointer is updated to the directory containing the
  1682.  *  actual file.  Return the file node or NULL if not found.  If the
  1683.  *  path is illegal (an intermediate directory was not found), set *ppar
  1684.  *  to NULL and return NULL.
  1685.  *
  1686.  *  *ppar may also be set to NULL if the search path IS the root.
  1687.  *
  1688.  *  If pptr not NULL, Set *pptr to the final component in the path.
  1689.  */
  1690.  
  1691. RAMFILE *
  1692. searchpath(ppar,buf,pptr)
  1693. RAMFILE **ppar;
  1694. char *buf;
  1695. char **pptr;
  1696. {
  1697.     RAMFILE *file = *ppar;
  1698.     RAMFILE *srch;
  1699.     short len;
  1700.     char *ptr;
  1701.  
  1702.     *ppar = NULL;
  1703.     for (;*buf && file;) {
  1704.     ptr = getpathelement(&buf,&len);
  1705.     if (buf[0] == ':') {    /*  go to root          */
  1706.         ++buf;
  1707.         file = &RFRoot;
  1708.         continue;
  1709.     }
  1710.     if (*ptr == '/') {          /*  go back a directory */
  1711.         if (!file->parent) {    /*    no parent directory */
  1712.         return(NULL);
  1713.         }
  1714.         file = file->parent;
  1715.         continue;
  1716.     }
  1717.     if (file->type == FILE_FILE)
  1718.         return(NULL);
  1719.     for (srch = GetHead(&file->list); srch; srch = NextNode(srch)) {
  1720.         if (srch->type && strlen(srch->name) == len && nccmp(srch->name, ptr, len)) {
  1721.         file = srch;        /*    element found        */
  1722.         break;
  1723.         }
  1724.     }
  1725.     if (srch == NULL) {
  1726.         if (*buf == 0)    /*  Element not found.    If it was the final */
  1727.         *ppar = file;    /*  element the parent directory is valid   */
  1728.         if (pptr)
  1729.         *pptr = ptr;
  1730.         return(NULL);
  1731.     }
  1732.     }
  1733.     if (pptr)
  1734.     *pptr = ptr;
  1735.     *ppar = file->parent;
  1736.     return(file);
  1737. }
  1738.  
  1739. /*
  1740.  *  Return the next path element in the string.  The routine effectively
  1741.  *  removes any trailing '/'s, but treats ':' as part of the next component
  1742.  *  (i.e. ':' is checked and skipped in SEARCHPATH()).
  1743.  */
  1744.  
  1745. char *
  1746. getpathelement(pstr,plen)
  1747. char **pstr;
  1748. short *plen;
  1749. {
  1750.     char *base;
  1751.     register char *ptr = *pstr;
  1752.     register short len = 0;
  1753.  
  1754.     if (*(base = ptr)) {
  1755.     if (*ptr == '/') {
  1756.         ++ptr;
  1757.         ++len;
  1758.     } else {
  1759.         while (*ptr && *ptr != '/' && *ptr != ':') {
  1760.         ++ptr;
  1761.         ++len;
  1762.         }
  1763.         if (*ptr == '/')
  1764.         ++ptr;
  1765.     }
  1766.     }
  1767.     *pstr = ptr;
  1768.     *plen = len;
  1769.     return(base);
  1770. }
  1771.  
  1772.  
  1773. char *
  1774. typetostr(ty)
  1775. {
  1776.     switch(ty) {
  1777.     case ACTION_DIE:        return("DIE");
  1778.     case ACTION_OPENRW:     return("OPEN-RW");
  1779.     case ACTION_OPENOLD:    return("OPEN-OLD");
  1780.     case ACTION_OPENNEW:    return("OPEN-NEW");
  1781.     case ACTION_READ:        return("READ");
  1782.     case ACTION_WRITE:        return("WRITE");
  1783.     case ACTION_CLOSE:        return("CLOSE");
  1784.     case ACTION_SEEK:        return("SEEK");
  1785.     case ACTION_EXAMINE_NEXT:    return("EXAMINE NEXT");
  1786.     case ACTION_EXAMINE_OBJECT: return("EXAMINE OBJ");
  1787.     case ACTION_INFO:        return("INFO");
  1788.     case ACTION_DISK_INFO:    return("DISK INFO");
  1789.     case ACTION_PARENT:     return("PARENTDIR");
  1790.     case ACTION_DELETE_OBJECT:    return("DELETE");
  1791.     case ACTION_CREATE_DIR:    return("CREATEDIR");
  1792.     case ACTION_LOCATE_OBJECT:    return("LOCK");
  1793.     case ACTION_COPY_DIR:    return("DUPLOCK");
  1794.     case ACTION_FREE_LOCK:    return("FREELOCK");
  1795.     case ACTION_SET_PROTECT:    return("SETPROTECT");
  1796.     case ACTION_SET_COMMENT:    return("SETCOMMENT");
  1797.     case ACTION_RENAME_OBJECT:    return("RENAME");
  1798.     case ACTION_INHIBIT:    return("INHIBIT");
  1799.     case ACTION_RENAME_DISK:    return("RENAME DISK");
  1800.     case ACTION_MORECACHE:    return("MORE CACHE");
  1801.     case ACTION_WAIT_CHAR:    return("WAIT FOR CHAR");
  1802.     case ACTION_FLUSH:        return("FLUSH");
  1803.     case ACTION_RAWMODE:    return("RAWMODE");
  1804.     default:            return("---------UNKNOWN-------");
  1805.     }
  1806. }
  1807.  
  1808.  
  1809. /*
  1810.  *  DEBUGGING CODE.    You cannot make DOS library calls that access other
  1811.  *  devices from within a DOS device driver because they use the same
  1812.  *  message port as the driver.  If you need to make such calls you must
  1813.  *  create a port and construct the DOS messages yourself.  I do not
  1814.  *  do this.  To get debugging info out another PROCESS is created to which
  1815.  *  debugging messages can be sent.
  1816.  *
  1817.  *  You want the priority of the debug process to be larger than the
  1818.  *  priority of your DOS handler.  This is so if your DOS handler crashes
  1819.  *  you have a better idea of where it died from the debugging messages
  1820.  *  (remember that the two processes are asyncronous from each other).
  1821.  */
  1822.  
  1823. extern void debugproc();
  1824.  
  1825. dbinit()
  1826. {
  1827.     TASK *task = FindTask(NULL);
  1828.  
  1829.     if (!Dbport) {
  1830.  
  1831.     Dback = CreatePort(NULL,NULL);
  1832.     if((CreateProc("DEV_DB", task->tc_Node.ln_Pri+1, CTOB(debugproc), 4096)))
  1833.     {
  1834.     WaitPort(Dback);            /* handshake startup    */
  1835.     GetMsg(Dback);                /* remove dummy msg     */
  1836.     dbprintf("Debugger running V1.10, 2 November 1987\n");
  1837.     dbprintf("Works with WORKBENCH!\n");
  1838.     }
  1839.     else
  1840.     DeletePort(Dback);
  1841.  
  1842.     }
  1843. }
  1844.  
  1845. dbuninit()
  1846. {
  1847.     MSG killmsg;
  1848.  
  1849.     if (Dbport) {
  1850.     killmsg.mn_Length = 0;        /*    0 means die        */
  1851.     PutMsg(Dbport,&killmsg);
  1852.     WaitPort(Dback);        /*    He's dead jim!      */
  1853.     GetMsg(Dback);
  1854.     DeletePort(Dback);
  1855.     Dbport = 0;
  1856.  
  1857.     /*
  1858.      *  Since the debug process is running at a greater priority, I
  1859.      *  am pretty sure that it is completely removed
  1860.      *  before this task gets control again.  Still, it doesn't hurt...
  1861.      */
  1862.  
  1863.     Delay(50);            /*    ensure he's dead    */
  1864.     }
  1865. }
  1866.  
  1867. dbprintf(a,b,c,d,e,f,g,h,i,j)
  1868. {
  1869.     char buf[256];
  1870.     MSG *msg;
  1871.  
  1872.     if (Dbport && !DBDisable) {
  1873.     sprintf(buf,a,b,c,d,e,f,g,h,i,j);
  1874.     msg = AllocMem(sizeof(MSG)+strlen(buf)+1, MEMF_PUBLIC|MEMF_CLEAR);
  1875.     msg->mn_Length = strlen(buf)+1;     /*    Length NEVER 0    */
  1876.     strcpy(msg+1,buf);
  1877.     PutMsg(Dbport,msg);
  1878.     }
  1879. }
  1880.  
  1881. /*
  1882.  *  BTW, the DOS library used by debugmain() was actually openned by
  1883.  *  the device driver.    Note: DummyMsg cannot be on debugmain()'s stack
  1884.  *  since debugmain() goes away on the final handshake.
  1885.  */
  1886.  
  1887. debugmain()
  1888. {
  1889.     MSG *msg;
  1890.     short len;
  1891.     void *fh;
  1892.  
  1893.     Dbport = CreatePort(NULL,NULL);
  1894.     fh = Open("con:0/0/640/100/debugwindow", 1006);
  1895.     PutMsg(Dback, &DummyMsg);
  1896.     for (;;) {
  1897.     WaitPort(Dbport);
  1898.     msg = GetMsg(Dbport);
  1899.     len = msg->mn_Length;
  1900.     if (len == 0)
  1901.         break;
  1902.     --len;                  /*  Fix length up   */
  1903.     Write(fh, msg+1, len);
  1904.     FreeMem(msg,sizeof(MSG)+len+1);
  1905.     }
  1906.     Close(fh);
  1907.     DeletePort(Dbport);
  1908.     PutMsg(Dback,&DummyMsg);          /*  Kill handshake  */
  1909. }
  1910.  
  1911.  
  1912.  
  1913. #ifdef BEVIRTUAL
  1914.  
  1915. #ifdef TESTING
  1916.  
  1917. /*
  1918.  *  Patch Data I/O functions directly to owner device
  1919.  *
  1920.  */
  1921.  
  1922.  
  1923. void
  1924. patchpacket2()
  1925. {
  1926.  
  1927.     for(;;)
  1928.     {
  1929.         for(x=0;x<9999;x++)
  1930.         {
  1931.             if(!getnextdev("name")) break;
  1932.             if(dev->VolDays != mydev->VolDays)
  1933.                 continue;
  1934.             else
  1935.             {
  1936.             /* We found the device, now patch thru to it */
  1937.             /* AmigaDOS-TR p271: "AmigaDOS maintains all other fields" */
  1938.             /* so I guess, being AmigaDOS, I have to be nice */
  1939. /*
  1940.             - copy the packet
  1941.             - replace name with original full path name
  1942.             - issue the packet
  1943.             - wait for reply
  1944.             - return reply to host
  1945.  */
  1946.             }
  1947.         }
  1948.         /* if(!(Request("Insert Disk X")))break; else continue; */
  1949.     }
  1950. }
  1951.  
  1952.  
  1953.     /* to send a packet:
  1954.  
  1955.    struct MsgPort        *replyport;
  1956.    replyport = (struct MsgPort *) CreatePort(NULL,0);
  1957.    if(!replyport) return(0L);
  1958.    PutMsg(pid,(struct Message *)packet);
  1959.    WaitPort(replyport);
  1960.    GetMsg(replyport); 
  1961.    DeletePort(replyport); 
  1962.  
  1963.     note that deviceproc does quite a handy job of requesting a name
  1964.     perhaps it calls some semi-generic routine?
  1965.  
  1966.     */
  1967.  
  1968.                 {
  1969.                 register struct Message *mess;
  1970.                 register struct MsgPort *replyport;
  1971.                 mess = packet->dp_Link;
  1972.                 mess->mn_Node.ln_Name = (char *)packet;
  1973.                 mess->mn_Node.ln_Succ = NULL;
  1974.                 mess->mn_Node.ln_Pred = NULL;
  1975.                 PutMsg(MyDevNode->dn_Task,mess);
  1976.                 /* now forget about the packet completely! */
  1977.             goto forgotten;
  1978.             }
  1979.  
  1980.  
  1981.  
  1982. #ifdef BETESTING
  1983. /*********************************************************/
  1984.     {
  1985.     register struct Message *mmouess;
  1986.     register struct MsgPort *replyport;
  1987.     DEVNODE    *MyDevNode;
  1988.     if(!(MyDevNode = FindHandler("scratch:",DOSBase)))  /* and key */
  1989.         { dbprintf("Device not found!\n"); }
  1990.         else
  1991.         {
  1992.         mess = packet->dp_Link;
  1993.         mess->mn_Node.ln_Name = (char *)packet;
  1994.         mess->mn_Node.ln_Succ = NULL;
  1995.         mess->mn_Node.ln_Pred = NULL;
  1996.         PutMsg(MyDevNode->dn_Task,mess);
  1997.         /* now forget about the packet completely! */
  1998.         /*goto forgotten;*/
  1999.         }
  2000.     }
  2001. /*********************************************************/
  2002. #endif
  2003.  
  2004. /*
  2005.  *    rather than replying to a packet; pass it off to its real
  2006.  *    destination, in such a way that the client feels like he is
  2007.  *    talking directly with the third party - this permits me to
  2008.  *    drop out of the process without having to handle to crosstalk.  AH
  2009.  
  2010.     (this function is commented out for the moment in favour of the
  2011.      absolutely most robust solution [ see sendpacket below ]...later on
  2012.     if this is stable i may turn this back on...its moderately faster
  2013.     and mongo coolo.
  2014.  
  2015.  */
  2016.  
  2017. patchpacket(packet,mdest)
  2018. register struct DosPacket *packet;
  2019. register struct MsgPort *mdest;
  2020. {
  2021.     register struct Message *mess;
  2022.  
  2023.     mess            = packet->dp_Link;    /* address of packet */
  2024.     /* packet->dp_Port */                /* originator same!!*/
  2025.     mess->mn_Node.ln_Name    = (char *)packet;    /* my message */
  2026.     mess->mn_Node.ln_Succ    = NULL;
  2027.     mess->mn_Node.ln_Pred    = NULL;
  2028.     PutMsg(mdest,mess);                /* don't wait!!! */
  2029. }
  2030.  
  2031.  
  2032. #endif TESTING
  2033.  
  2034.  
  2035.  
  2036. /*
  2037.  *    send a packet to a third party, but act as a mediator
  2038.  *    intercepting the reply and returning with it to higher
  2039.  *    level routines which will act based on response.  AH
  2040.  *
  2041.  */
  2042.  
  2043. sendpacket(packet,dest)
  2044. register struct DosPacket *packet;
  2045. register struct MsgPort *dest;
  2046. {
  2047.     register struct Message *mess;
  2048.     struct MsgPort *replyport;
  2049.  
  2050.     replyport = (struct MsgPort *) CreatePort(NULL,0);
  2051.     if(!replyport) return(0L);
  2052.  
  2053.     mess            = packet->dp_Link;
  2054.     packet->dp_Port        = replyport; /* comes back to me */
  2055.     mess->mn_Node.ln_Name    = (char *)packet;
  2056.     mess->mn_Node.ln_Succ    = NULL;
  2057.     mess->mn_Node.ln_Pred    = NULL;
  2058.     PutMsg(dest,mess);
  2059.     WaitPort(replyport);
  2060.     GetMsg(replyport);
  2061.     DeletePort(replyport);
  2062.     return(1);
  2063. }
  2064.  
  2065.  
  2066.  
  2067.  
  2068. /*
  2069.  *    read from my own ram disk.  AH
  2070.  */
  2071.  
  2072. int
  2073. myreadsome(mptr,mfen,mleft) /* return total read */
  2074. ubyte *mptr;    /* ptr = destination */
  2075. FENTRY *mfen;    /* node list of bits of RAM */
  2076. int mleft;    /* desired amount */
  2077. {
  2078.     register long scr;  long *start = mptr;
  2079.  
  2080.     int    mtotal;    /* always returns 0? bug */
  2081.  
  2082.     mtotal = 0;
  2083.  
  2084.     dbprintf("readsome left, fen->bytes %ld %ld\n",mleft,mfen->bytes);
  2085.  
  2086.     while (mleft && mfen) {
  2087.         scr = mfen->bytes;    /* bytes here */
  2088.         if (mleft < scr) {    /* desired < available */
  2089.             bmov(mfen->buf, mptr, mleft);
  2090.             mtotal += mleft;
  2091.             mleft = 0;    /* done! */
  2092.             }
  2093.             else {        /* move what I can, goto next node */
  2094.             bmov(mfen->buf, mptr, scr);
  2095.             mleft -= scr;    /* decrease desired */
  2096.             mtotal += scr;
  2097.             mptr += scr;    /* increase write dest */
  2098.             mfen = NextNode(mfen);
  2099.             }
  2100.         }
  2101.  
  2102. /* once i've got the file just check here to make sure its a virtual instance
  2103.    normally I only read around a hundred bytes...so even if this isn't a virtual
  2104.    file there isn't a tremendous wastage of overhead... */
  2105.  
  2106.     if ( *start !=VIRT) return(0);
  2107.  
  2108.     dbprintf("total is %ld\n",mtotal);
  2109.  
  2110.     return(mtotal);
  2111. }
  2112.  
  2113. #endif
  2114.  
  2115.  
  2116.  
  2117. #ifdef COMMENT
  2118.  
  2119. /* Returned by Examine() and ExNext(), must be on a 4 byte boundary */
  2120. struct FileInfoBlock {
  2121.    LONG      fib_DiskKey;
  2122.    LONG      fib_DirEntryType;  /* Type of Directory. If < 0, then a plain file.
  2123.                   * If > 0 a directory */
  2124.    char      fib_FileName[108]; /* Null terminated. Max 30 chars used for now */
  2125.    LONG      fib_Protection;    /* bit mask of protection, rwxd are 3-0.       */
  2126.    LONG      fib_EntryType;
  2127.    LONG      fib_Size;         /* Number of bytes in file */
  2128.    LONG      fib_NumBlocks;     /* Number of blocks in file */
  2129.    struct DateStamp fib_Date;/* Date file last changed */
  2130.    char      fib_Comment[80];  /* Null terminated comment associated with file */
  2131.    char      fib_Reserved[36];
  2132. }; /* FileInfoBlock */
  2133. #endif
  2134.  
  2135.  
  2136. /*
  2137.  
  2138. *    need to check for the key also
  2139. -    need to put up a "please insert disk x":
  2140.         this requestor should have a variable length timeout
  2141.         this requestor should accept an alternate file path
  2142.         this requestor should have button for "just use df0:"
  2143.         cancel and accept will also be there
  2144.         as well i must keep perusing the device list...
  2145. *    need to imbed the checksum in returned fib (somewhere safe)
  2146. *    if file is not virtual do i call myreadsome anyway??? (YES)
  2147. -    any weaknesses in matts driver in general?
  2148. -    a compile may fail if buffer is not longword aligned.
  2149.     may want to have some kind of runtime, or half-compile time check!
  2150. -    device driver should checksum itself, and checksum its files, being
  2151.     a ram device and prone to external trashing
  2152. -    matt screws around with the diskkey...he shouldn't do that...
  2153. -    replace viblen with sizeofvib
  2154. -    there *must* be a "bestupid" mode which checks with much less rigour
  2155. -    when i find a devnode i should lock it (but how do i do that???)
  2156. *    blocks used is buggy
  2157. *    what if the vir: passes of a packet and the silly dest isn't there?
  2158.     does vir: close its own copy????
  2159.  */
  2160.  
  2161.